package top.blackr.folivora.common.security;

import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.filter.SaServletFilter;
import cn.dev33.satoken.interceptor.SaInterceptor;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.dreamlu.mica.core.result.R;
import net.dreamlu.mica.redis.cache.MicaRedisCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import top.blackr.folivora.common.core.constants.CommonConstants;
import top.blackr.folivora.config.ApplicationProperties;

/**
 * @author BlackR
 */
@Slf4j
@AllArgsConstructor
@SpringBootConfiguration
public class SecurityWebMvcConfig implements WebMvcConfigurer {

    private final MicaRedisCache redisCache;
    private final ApplicationProperties.Security securityProperties;
    private final FilterAuthStrategy filterAuthStrategy;
    private final BeforeAuthFilterAuthStrategy beforeAuthFilterAuthStrategy;

    /**
     * 注册 [Sa-Token全局过滤器]
     */
    @Bean
    public SaServletFilter saServletFilter() {
        return new SaServletFilter()
                // 指定 拦截路由 与 放行路由
//                .addInclude("/**")
                // 排除掉
                .addExclude(securityProperties.getIgnoredUrls().toArray(new String[0]))
                // 前置函数：在每次认证函数之前执行
                .setBeforeAuth(beforeAuthFilterAuthStrategy)
                // 认证函数: 每次请求执行
                .setAuth(filterAuthStrategy)
                // 异常处理函数：每次认证函数发生异常时执行此函数
                .setError(throwable -> {
                    log.debug("---------- 进入Sa-Token异常处理 -----------", throwable);
                    return R.fail(throwable.getMessage());
                });
    }

    /**
     * 此配置会与 application.yml 中的配置合并 （代码配置优先）
     */
    @Autowired
    public void saTokenConfigPrimary(SaTokenConfig config) {
        // token 有效期（单位：秒），默认30天，-1代表永不过期
        config.setTimeout(securityProperties.getTokenExpireTime())
                .setTokenPrefix("Bearer")
                .setTokenName(CommonConstants.TOKEN_NAME)
                // 在初始化配置时不打印版本字符画
                .setIsPrint(false)
                // 不尝试从 cookie 里读取 Token
                .setIsReadCookie(false)
                // 不尝试从 请求体 里读取 Token
                .setIsReadBody(false)
                // 在多人登录同一账号时，共用一个token
                .setIsShare(true)
                // 不允许同一账号并发登录，新登录挤掉旧登录
                .setIsConcurrent(false)
                // 打印彩色日志
                .setIsColorLog(true)
                // token有效期，单位s 默认30天, -1代表永不过期
                .setTimeout(2592000)
                // token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒
                .setActiveTimeout(-1)
                // token风格
                .setTokenStyle("uuid")
                // 是否输出操作日志
                .setIsLog(false);
    }


    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 开启注解权限校验
        registry.addInterceptor(new SaInterceptor()).addPathPatterns("/**");
        registry.addInterceptor(new UserInfoInterceptor(redisCache)).addPathPatterns("/**");
    }
}